﻿using System;
using System.Collections.Generic;
using System.Text;
using VMExplorer.Win32;

namespace VMExplorer.MemoryObjects
{
  abstract class HeapEntry
  {
    #region ChunkHeader class

    public class ChunkHeader : RemoteTypeWrapper<Native.HEAP_ENTRY>
    {
      #region Construction

      public ChunkHeader (SafeProcessHandle hProcess, MemoryAddress baseAddress)
        : base (hProcess, baseAddress)
      {
      }

      #endregion

      public UInt16 Size { get { return Inner.Size; } }
      public Native.HEAP_ENTRY_FLAGS EntryFlags { get { return Inner.EntryFlags; } }
      public byte UnusedBytes { get { return Inner.UnusedBytes; } }
      public byte SegmentIndex { get { return Inner.SegmentIndex; } }
    }

    #endregion
    #region RegionType enum

    public enum RegionType
    {
      Free,
      Busy,
      Region,
      Uncommited,
    }

    #endregion
    #region Private fields

    protected ChunkHeader _chunkHeader;

		#endregion
		#region Public properties

		public virtual MemoryAddress Base { get { return _chunkHeader.BaseAddress; } }
		public virtual MemoryAddress Data { get { return Base + HeaderSize; } }
		public virtual int ChunkSize { get { return _chunkHeader.Size * 8; } }
		public virtual int HeaderSize { get { return 8; } }
		public virtual int DataSize { get { return ChunkSize - _chunkHeader.UnusedBytes; } }
		public virtual int PadSize { get { return _chunkHeader.UnusedBytes - HeaderSize; } }
		public virtual int SegmentIndex { get { return _chunkHeader.SegmentIndex; } }
		public virtual bool IsLastEntry { get { return ((_chunkHeader.EntryFlags & Native.HEAP_ENTRY_FLAGS.LastEntry) == Native.HEAP_ENTRY_FLAGS.LastEntry); } }

    public RegionType Type { get; private set;  }

		#endregion
		#region Construction

		protected HeapEntry (ChunkHeader chunkHeader, RegionType type)
		{
			_chunkHeader = chunkHeader;
      Type = type;
		}

		public static HeapEntry Create (SafeProcessHandle hProcess, MemoryAddress baseAddress)
		{
			ChunkHeader chunkHeader = new ChunkHeader (hProcess, baseAddress);

			if ((chunkHeader.EntryFlags & Native.HEAP_ENTRY_FLAGS.Busy) == 0)
			{
				return new HeapEntryFree (chunkHeader);
			}
			return new HeapEntryBusy (chunkHeader);
		}

		#endregion
	}

	class HeapEntryFree : HeapEntry
  {
    #region Construction

    public HeapEntryFree (ChunkHeader chunkHeader)
			: base (chunkHeader, RegionType.Free)
		{ }

		public HeapEntryFree (SafeProcessHandle hProcess, MemoryAddress baseAddress)
			: this(new ChunkHeader (hProcess, baseAddress))
		{ }

    #endregion
    #region HeapEntry overrides

		public override int HeaderSize { get { return 16; } }
		public override int DataSize { get { return _chunkHeader.Size * 8 - 16; } }

    #endregion
  }

	class HeapEntryRegion : HeapEntry
  {
    #region Construction

    public HeapEntryRegion (ChunkHeader chunkHeader)
      : base(chunkHeader, RegionType.Region)
		{ }

		public HeapEntryRegion (SafeProcessHandle hProcess, MemoryAddress baseAddress)
			: this(new ChunkHeader (hProcess, baseAddress))
		{ }

    #endregion
    #region HeapEntry overrides

		public override MemoryAddress Data { get { return Base; } }
		public override int HeaderSize { get { return _chunkHeader.Size * 8; } }
		public override int DataSize { get { return 0; } }

    #endregion
  }

	class HeapEntryUncommitted : HeapEntry
  {
    #region Private fields

    private MemoryAddress _baseAddress;
		private int _size;

    #endregion
    #region Construction

    public HeapEntryUncommitted (MemoryAddress baseAddress, int size)
      : base(null, RegionType.Uncommited)
		{
			_baseAddress = baseAddress;
			_size = size;
    }

    #endregion
    #region HeapEntry overrides

		public override MemoryAddress Base { get { return _baseAddress; } }
		public override MemoryAddress Data { get { return _baseAddress; } }
		public override int ChunkSize { get { return _size; } }
		public override int HeaderSize { get { return 0; } }
		public override int DataSize { get { return _size; } }
		public override int PadSize { get { return 0; } }
		public override int SegmentIndex { get { return -1; } }
		public override bool IsLastEntry { get { return true; } }

    #endregion
  }

	class HeapEntryBusy : HeapEntry
  {
    #region Construction

    public HeapEntryBusy (ChunkHeader chunkHeader)
      : base(chunkHeader, RegionType.Busy)
		{ }

		public HeapEntryBusy (SafeProcessHandle hProcess, MemoryAddress baseAddress)
			: this(new ChunkHeader (hProcess, baseAddress))
		{ }

    #endregion
  }
}
